// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: daniel

#pragma once

#include <memory>
#include <utility>

#include "coin2/exchange/base/order/rate_tracker.h"
#include "coin2/exchange/order/connection.pb.h"

class FtxRateTracker : public coin2::exchange::base::order::IRateTracker {
 public:
  using RateTracker = coin2::exchange::base::order::RateTracker;
  using ActionType = coin2::exchange::base::order::IRateTracker::ActionType;
  using RateLimitReportWriter = coin2::exchange::base::order::RateLimitReportWriter;

 public:
  explicit FtxRateTracker(int64_t window_size)
      : rate_tracker_{std::make_unique<RateTracker>(window_size)},
        rate_limit_report_writer_{std::make_unique<RateLimitReportWriter>()} {}

  void SetRateLimitInfo(int32_t rate_limit, int32_t rate_limit_remaining) override {
    rate_tracker_->SetRateLimitInfo(rate_limit, rate_limit_remaining);
  }

  bool HasEnoughRateLimit(int64_t timestamp, ActionType action_type) override {
    if (action_type == ActionType::PLACE || action_type == ActionType::CANCEL) {
      return true;
    }
    auto ret = rate_tracker_->HasEnoughRateLimit(timestamp);
    if (!ret) {
      rate_limit_report_writer_->SetHitRateLimit(timestamp, action_type);
    }
    return ret;
  }

  void Push(int32_t num_reqs, int64_t timestamp, [[maybe_unused]] ActionType action_type) override {
    rate_tracker_->Push(num_reqs, timestamp);
  }

  void ParseRateLimitInfo(
      [[maybe_unused]] const std::shared_ptr<AsioHttpContext>& http_context,
      [[maybe_unused]] ActionType action_type) override {}

  void SetRateLimitInfoString(const google::protobuf::Message* message) override {
    rate_limit_report_writer_->SetRateLimitInfoString(message);
  }

  void WriteRateLimitReportMessage(OrderLoggerCB callback) override {
    if (!callback) {
      return;
    }
    rate_limit_report_writer_->Write(callback);
  }

  double GetMaxRateUsedRatio(int64_t timestamp, ActionType action_type) override {
    if (action_type == ActionType::PLACE || action_type == ActionType::CANCEL) {
      return 0.;
    }
    auto max_reqs = rate_tracker_->MaxReq();
    auto remaining = rate_tracker_->GetRemaining(timestamp);
    return 1.0 * (max_reqs - remaining) / max_reqs;
  }

 private:
  std::unique_ptr<RateTracker> rate_tracker_;
  std::unique_ptr<RateLimitReportMessage> rate_limit_report_msg_;
  std::unique_ptr<RateLimitReportWriter> rate_limit_report_writer_;
};
